﻿using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;

namespace LcfContols.DataBase.MySQL
{
    /// <summary>
    /// 执行SQL的代理
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="args"></param>
    /// <returns></returns>
    public delegate T ExecuteDelegate<T>(MySqlConnection conn, MySqlCommand cmd);

    /// <summary>
    /// 数据库异常代理
    /// </summary>
    /// <param name="ex"></param>
    public delegate void DataError(LDataException ex);
    
    /// <summary>
    /// 数据库操作
    /// </summary>
    public class DataBase
    {
        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        private string connectString = null;
        
        /// <summary>
        /// 异常错误事件
        /// </summary>
        public event DataError error;

        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        public string ConnectStr
        {
            get
            {
                return connectString;
            }
        }

        /// <summary>
        /// 数据库操作
        /// </summary>
        /// <param name="ip">数据库IP</param>
        /// <param name="username">账号</param>
        /// <param name="password">密码</param>
        /// <param name="database">数据库名称</param>
        /// <param name="charset">数据字符编码</param>
        /// <param name="port">数据库端口号</param>
        public DataBase(string ip, string username, string password, string database, string charset = "utf8", uint port = 3306)
        {
            connectString = Sql.CreateConnectString(ip, username, password, database, charset, port);
        }

        /// <summary>
        /// 抛出一个异常
        /// </summary>
        /// <param name="exMessage"></param>
        /// <returns></returns>
        public void ThrowException(String exMessage)
        {
            LDataException ex = new LDataException(exMessage);
            if (error != null)
                error(ex);
            else
                throw ex;
        }


        /// <summary>
        /// 执行SQL，封装了数据的连接以及命令创建
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fun"></param>
        /// <returns></returns>
        public T Execute<T>(ExecuteDelegate<T> fun)
        {
            using (MySqlConnection conn = new MySqlConnection(ConnectStr))
            {
                try
                {
                    conn.Open();
                    using(MySqlCommand cmd = conn.CreateCommand())
                    {
                        return fun(conn, cmd);
                    }
                }catch(DbException ex){
#if DEBUG
                    Console.WriteLine(ex.Message);
#endif
                    ThrowException(ex.Message);
                }
            }
            return default(T);
        }

        /// <summary>
        /// 执行事务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fun"></param>
        /// <returns></returns>
        public T Transaction<T>(ExecuteDelegate<T> fun, IsolationLevel iso =IsolationLevel.ReadCommitted)
        {
            using (MySqlConnection conn = new MySqlConnection(ConnectStr))
            {
                try
                {
                    conn.Open();
                    using (MySqlCommand cmd = conn.CreateCommand())
                    {
                        cmd.Transaction = conn.BeginTransaction(iso);
                        try{
                            T result = fun(conn, cmd);
                            cmd.Transaction.Commit(); //提交数据
                            return result;
                        }
                        catch (DbException ex)
                        {
                            cmd.Transaction.Rollback();
                            throw ex;
                        }
                    }
                }
                catch (DbException ex)
                {
#if DEBUG
                    Console.WriteLine(ex.Message);
#endif
                    ThrowException(ex.Message);
                }
            }
            return default(T);
        }

    }

    /// <summary>
    /// 自定义数据库查询错误
    /// </summary>
    public class LDataException:DbException
    {
        public LDataException() : base() { }
        public LDataException(string message) : base(message) { }
        public LDataException(SerializationInfo info, StreamingContext context) : base(info, context) { }
        public LDataException(string message, int errorCode) : base(message, errorCode) { }
        public LDataException(string message, Exception innerException) : base(message, innerException) { }
    }
}
